package com.hqq.helper;

import com.hqq.annotation.Aspect;
import com.hqq.annotation.Service;
import com.hqq.annotation.Transaction;
import com.hqq.proxy.AspectProxy;
import com.hqq.proxy.Proxy;
import com.hqq.proxy.ProxyManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.annotation.Annotation;
import java.util.*;

/**
 * AopHelper
 * 方法拦截助手类
 * Created by heqianqian on 2017/7/21.
 */
public class AopHelper {

    private static final Logger LOGGER = LoggerFactory.getLogger(AopHelper.class);

    public static void init() {
        System.out.println("init in AopHelper");
        Map<Class<?>, Set<Class<?>>> proxyMap = createProxyMap();
        Map<Class<?>, List<Proxy>> targetMap = createTargetMap(proxyMap);
        for (Map.Entry<Class<?>, List<Proxy>> targetEntry : targetMap.entrySet()) {
            Class<?> targetClass = targetEntry.getKey();
            List<Proxy> proxyList = targetEntry.getValue();
            Object proxy = ProxyManager.createProxy(targetClass, proxyList);
            BeanHelper.setBean(targetClass, proxy);
        }
    }

    /**
     * 获取Aspect注解设置的所有目标类集合
     *
     * @param aspect Aspect注解
     * @return Set<Class>
     */
    public static Set<Class<?>> getTargetClassSet(Aspect aspect) {
        Set<Class<?>> classSet = new HashSet<>();
        Class<? extends Annotation> annotation = aspect.value();
        if (!annotation.equals(Aspect.class)) {
            classSet.addAll(ClassHelper.getAnnotationClass(annotation));
        }
        return classSet;
    }

    /**
     * 获取目标类和代理类的映射关系
     *
     * @return Map<Class,Set<Class>>
     */
    public static Map<Class<?>, Set<Class<?>>> createProxyMap() {
        Map<Class<?>, Set<Class<?>>> proxyMap = new HashMap<>();
        //获取所有的代理类
        addAspectProxy(proxyMap);
        addTransactionProxy(proxyMap);
        return proxyMap;
    }

    /**
     * 添加Aspect注解类
     */
    private static void addAspectProxy(Map<Class<?>, Set<Class<?>>> proxyMap) {
        Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
        for (Class<?> proxyClass : proxyClassSet) {
            if (proxyClass.isAnnotationPresent(Aspect.class)) {
                Aspect aspect = proxyClass.getAnnotation(Aspect.class);
                Set<Class<?>> target = getTargetClassSet(aspect);
                proxyMap.put(proxyClass, target);
            }
        }
    }
    /**
     * 添加Transaction代理类
     */
    private static void addTransactionProxy(Map<Class<?>, Set<Class<?>>> proxyMap) {
        Set<Class<?>> serviceClassesSet = ClassHelper.getAnnotationClass(Service.class);
        proxyMap.put(Transaction.class, serviceClassesSet);
    }

    /**

     * 获取目标类和代理列表的关系
     *
     * @return Map<Class<?>, List<Proxy>>
     */
    private static Map<Class<?>, List<Proxy>> createTargetMap(Map<Class<?>, Set<Class<?>>> proxyMap) {
        Map<Class<?>, List<Proxy>> targetMap = new HashMap<>();
        try {
            for (Map.Entry<Class<?>, Set<Class<?>>> entry : proxyMap.entrySet()) {
                Class<?> targetClass = entry.getKey();
                Set<Class<?>> targetClassSet = entry.getValue();
                for (Class<?> clazz : targetClassSet) {
                    Proxy proxy = (Proxy) clazz.newInstance();
                    if (targetMap.containsKey(targetClass)) {
                        targetMap.get(targetClass).add(proxy);
                    } else {
                        List<Proxy> proxyList = new ArrayList<>();
                        proxyList.add(proxy);
                        targetMap.put(targetClass, proxyList);
                    }
                }
            }
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage());
        }
        return targetMap;
    }
}
